#version 330 core
layout(points) in;
layout(triangle_strip, max_vertices = 48) out;

in vec3 vNormal[];

uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;

// 绘制箭头
void DrawArrow(mat4 trsf, vec3 dir1, vec3 dir2);
void DrawSide(mat4 trsf, vec3 dir1, vec3 dir2);
void DrawBottom(mat4 trsf, vec3 dir1, vec3 dir2);

void main()
{
    // 原始顶点进行偏移
    vec4 position = gl_in[0].gl_Position;
    vec3 normal = vNormal[0];

    // 注意不能使用列表初始化，需要先定义数组，然后分别赋值
    vec3 v[3];
    v[0] = vec3(1, 0, 0);
    v[1] = vec3(0, 1, 0);
    v[2] = vec3(0, 0, 1);
    float p[3];
    for (int i = 0; i < 3; i++)
        p[i] = abs(dot(normal, v[i]));

    // 记录最大投影的索引
    int ind = 0;
    float mp = p[0];
    for (int i = 1; i < 3; i++)
    {
        if (p[i] < mp)
        {
            mp = p[i];
            ind = i;
        }
    }

    // 变换矩阵
    mat4 trsf = projection * view * model;

    // 绘制 4 个方向
    vec3 dir1 = cross(v[ind], normal);
    vec3 dir2 = cross(normalize(normal), dir1);

    DrawArrow(trsf, dir1, dir2);
    DrawSide(trsf, dir1, dir2);
    DrawBottom(trsf, dir1, dir2);
}

void DrawArrow(mat4 trsf, vec3 dir1, vec3 dir2)
{
    float ratio = 0.02;
    vec4 position = gl_in[0].gl_Position + vec4(vNormal[0], 0) * 0.9;

    vec4 offset0 = vec4(vNormal[0], 0) * ratio * 8;
    vec4 offset1 = vec4(dir1, 0) * ratio * 4;
    vec4 offset2 = vec4(dir2, 0) * ratio * 4;

    // 1 面
    gl_Position = trsf * position;
    EmitVertex();

    gl_Position = trsf * (position + offset1 - offset0);
    EmitVertex();

    gl_Position = trsf * (position + offset2 - offset0);
    EmitVertex();

    EndPrimitive();

    // 2 面
    gl_Position = trsf * position;
    EmitVertex();

    gl_Position = trsf * (position - offset1 - offset0);
    EmitVertex();

    gl_Position = trsf * (position + offset2 - offset0);
    EmitVertex();

    EndPrimitive();

    // 3 面
    gl_Position = trsf * position;
    EmitVertex();

    gl_Position = trsf * (position - offset1 - offset0);
    EmitVertex();

    gl_Position = trsf * (position - offset2 - offset0);
    EmitVertex();

    EndPrimitive();

    // 4 面
    gl_Position = trsf * position;
    EmitVertex();

    gl_Position = trsf * (position + offset1 - offset0);
    EmitVertex();

    gl_Position = trsf * (position - offset2 - offset0);
    EmitVertex();

    EndPrimitive();

    // 5 面
    gl_Position = trsf * (position + offset1 - offset0);
    EmitVertex();

    gl_Position = trsf * (position - offset1 - offset0);
    EmitVertex();

    gl_Position = trsf * (position + offset2 - offset0);
    EmitVertex();

    EndPrimitive();

    // 6 面
    gl_Position = trsf * (position + offset1 - offset0);
    EmitVertex();

    gl_Position = trsf * (position - offset1 - offset0);
    EmitVertex();

    gl_Position = trsf * (position - offset2 - offset0);
    EmitVertex();

    EndPrimitive();
}

void DrawSide(mat4 trsf, vec3 dir1, vec3 dir2)
{
    float ratio = 0.02;
    vec4 normal = vec4(vNormal[0], 0) * 0.8;
    vec4 position = gl_in[0].gl_Position + vec4(vNormal[0], 0) * 0.1;

    vec4 offset0 = vec4(vNormal[0], 0) * ratio * 4;
    vec4 offset1 = vec4(dir1, 0) * ratio;
    vec4 offset2 = vec4(dir2, 0) * ratio;

    // 1 侧
    gl_Position = trsf * (position + offset1);
    EmitVertex();

    gl_Position = trsf * (position + offset2);
    EmitVertex();

    gl_Position = trsf * (position + normal + offset2 - offset0);
    EmitVertex();

    EndPrimitive();

    gl_Position = trsf * (position + offset1);
    EmitVertex();

    gl_Position = trsf * (position + normal + offset1 - offset0);
    EmitVertex();

    gl_Position = trsf * (position + normal + offset2 - offset0);
    EmitVertex();

    EndPrimitive();

    // 2 侧
    gl_Position = trsf * (position - offset1);
    EmitVertex();

    gl_Position = trsf * (position + offset2);
    EmitVertex();

    gl_Position = trsf * (position + normal + offset2 - offset0);
    EmitVertex();

    EndPrimitive();

    gl_Position = trsf * (position - offset1);
    EmitVertex();

    gl_Position = trsf * (position + normal - offset1 - offset0);
    EmitVertex();

    gl_Position = trsf * (position + normal + offset2 - offset0);
    EmitVertex();

    EndPrimitive();

    // 3 侧
    gl_Position = trsf * (position - offset1);
    EmitVertex();

    gl_Position = trsf * (position - offset2);
    EmitVertex();

    gl_Position = trsf * (position + normal - offset2 - offset0);
    EmitVertex();

    EndPrimitive();

    gl_Position = trsf * (position - offset1);
    EmitVertex();

    gl_Position = trsf * (position + normal - offset1 - offset0);
    EmitVertex();

    gl_Position = trsf * (position + normal - offset2 - offset0);
    EmitVertex();

    EndPrimitive();

    // 4 侧
    gl_Position = trsf * (position + offset1);
    EmitVertex();

    gl_Position = trsf * (position - offset2);
    EmitVertex();

    gl_Position = trsf * (position + normal - offset2 - offset0);
    EmitVertex();

    EndPrimitive();

    gl_Position = trsf * (position + offset1);
    EmitVertex();

    gl_Position = trsf * (position + normal + offset1 - offset0);
    EmitVertex();

    gl_Position = trsf * (position + normal - offset2 - offset0);
    EmitVertex();

    EndPrimitive();
}

void DrawBottom(mat4 trsf, vec3 dir1, vec3 dir2)
{
    float ratio = 0.02;
    vec4 normal = vec4(vNormal[0], 0);
    vec4 position = gl_in[0].gl_Position + normal * 0.1;

    vec4 offset1 = vec4(dir1, 0) * ratio;
    vec4 offset2 = vec4(dir2, 0) * ratio;

    // 1 底
    gl_Position = trsf * (position + offset1);
    EmitVertex();

    gl_Position = trsf * (position + offset2);
    EmitVertex();

    gl_Position = trsf * (position - offset2);
    EmitVertex();

    EndPrimitive();

    // 2 底
    gl_Position = trsf * (position - offset1);
    EmitVertex();

    gl_Position = trsf * (position + offset2);
    EmitVertex();

    gl_Position = trsf * (position - offset2);
    EmitVertex();

    EndPrimitive();
}
